@file:Suppress("UNCHECKED_CAST")

package com.virtualightning.mvvm.binding

import android.os.Build
import android.os.Looper
import android.util.Log
import com.virtualightning.mvvm.utils.AppUtils
import java.lang.ref.ReferenceQueue
import java.lang.ref.WeakReference

/**
 *  Anchor : Create by CimZzz
 *  Time : 2021/12/27 15:58
 *  全局观察主体池
 */
object SubjectPool {

	/**
	 * 引用的队列
	 */
	private val referenceQueue = ReferenceQueue<Subject<*>>()

	/**
	 * 观察主体池
	 */
	private var subjectPool: HashMap<String, InnerRef>? = null

	/**
	 * 将观察对象和观察主体进行绑定，若观察主体不存在，会生成一个新的观察主体
	 * @param observer ObserverLiveData<T> 观察对象
	 * @param key String 键值
	 * @param rewrite Boolean 是否重写观察主体数据
	 */
	fun <T> observe(observer: ObserverLiveData<T>, key: String?, rewrite: Boolean) {
		AppUtils.strictMainThread()
		evictPool()
		if (key.isNullOrEmpty() || observer.subjectType == -1) {
			return
		}
		val mixKey = "${observer.subjectType}\$$key"
		val pool = ensurePool()
		val subjectRef = pool[mixKey]
		if (subjectRef != null && !subjectRef.isRemoved) {
			val subject = subjectRef.get()
			if (subject != null) {
				// 如果类型不一致，这里会抛出异常，所以在绑定主体类型时一定要检查类型是否一致
				observer.assignSubject(subject as Subject<T>, rewrite)
				return
			} else {
				subjectRef.isRemoved = true
			}
		}

		val subject = Subject<T>(mixKey)
		pool[mixKey] = InnerRef(mixKey, subject, referenceQueue)
		observer.assignSubject(subject, rewrite)
	}

	///////////////////////////////////////////////////////////////////////////
	// 代码分割线 on 2021/12/27 4:54 下午 by CimZzz
	// 以下内容为:
	// 内部私有方法
	///////////////////////////////////////////////////////////////////////////

	/**
	 * 清理当前对象池
	 */
	private fun evictPool() {
		Looper.myQueue().addIdleHandler {
			var count = 0
			do {
				val ref = referenceQueue.poll() as? InnerRef ?: break
				count ++
				if(ref.isRemoved) {
					Log.v("CimZzz", "${ref.key} isRemoved")
					continue
				}
				this.subjectPool?.remove(ref.key)
				Log.v("CimZzz", "${ref.key} isRemoved")
			} while (count < 200)

			if(this.subjectPool?.isEmpty() == true) {
				// 不存在观察主体时，移除观察主体池
				this.subjectPool = null
			}

			// 每次执行 200 次，剩余部分放到下次 IdleHandler 触发时执行
			return@addIdleHandler count == 200
		}
	}

	/**
	 * 确保观察主体池存在
	 * @return HashMap<String, SubjectLiveData<*>> 观察主体池
	 */
	private fun ensurePool(): HashMap<String, InnerRef> {
		val subjectPool = this.subjectPool
		if (subjectPool != null) {
			return subjectPool
		}

		val newPool = HashMap<String, InnerRef>()
		this.subjectPool = newPool
		return newPool
	}

	/**
	 * 内部引用
	 */
	internal class InnerRef(
		/**
		 * 引用 Key 值
		 */
		val key: String,
		referent: Subject<*>,
		queue: ReferenceQueue<in Subject<*>>
	) : WeakReference<Subject<*>>(referent, queue) {
		var isRemoved: Boolean = false
	}
}